Next | Prev | Up | Top | Contents | Index
Entry Points read() and write()
The pfxread() and pfxwrite() entry points are similar to each other--only the direction of data transfer differs. The prototypes of the functions are
int pfxread (dev_t dev, uio_t *uiop, cred_t *crp);
int pfxwrite(dev_t dev, uio_t *uiop, cred_t *crp);
The arguments are
dev | A dev_t value from which you can extract both the major and minor device numbers. |
*uiop | A uio_t object--a structure that defines the user's buffer memory areas. |
crp | A cred_t object--an opaque structure for use in authentication. Standard access privileges to the special device file have already been verified. |
Data Transfer for a PIO Device
A character device driver using PIO transfers data in the following steps:
- If there is a possibility of a timeout, start a timeout delay (see "Waiting for Time to Pass").
- Initiate the device operation as required.
- Transfer data between the device and the buffer represented by the uio_t (see "Transferring Data Through a uio_t Object").
- If it is necessary to wait for an interrupt, put the process to sleep (see "Waiting and Mutual Exclusion").
- When data transfer is complete, or when an error occurs, clear any pending timeout and return the final status of the operation. If the return code is 0, the final state of the uio_t determines the byte count returned by the read() or write() call.
Calling Entry Point strategy() From Entry Point read() or write()
A device driver that supports both character and block interfaces must have a pfxstrategy() routine in which it performs the actual I/O. For example, the Silicon Graphics disk drivers support both character and block driver interfaces, and perform all I/O operations in the pfxstrategy() function. However, the pfxread(), pfxwrite() and pfxioctl() entries supported for character-type access also need to perform I/O operations. They do this by calling the pfxstrategy() routine indirectly, using the kernel function physiock() or uiophysio() (see the physiock(D3) and uiophysio(D3) reference pages, and see "Waiting for Block I/O to Complete").
Both the physiock() and uiophysio() functions takes care of the housekeeping needed to interface to the pfxstrategy() entry, including the work of allocating a buffer and a buf_t structure, locking buffer pages in memory and waiting for I/O completion. The physiock() function is preferable because it is compatible with SVR4. Example 8-1 shows the skeleton of a hypothetical driver in which the pfxread() entry does its work through the pfxstrategy() entry.
Example 8-1 : Hypothetical pfxread() entry in a Character/Block Driver
hypo_read (dev_t dev, uio_t *uiop, cred_t *crp)
{
// ...validate the operation... //
return physiock(hypo_strategy, /* our strategy entry */
0, /* allocate temp buffer & buf_t */
dev, /* dev_t arg for strategy */
B_READ, /* direction flag for buf_t */
uiop);
}
The pfxwrite() entry would be identical except for passing B_WRITE instead of B_READ.
This dual-entry strategy is required only in a driver that supports both character and block access. physiock() returns an error if the length requested in the uio_t object is not a multiple of the standard sector length, so a different approach is required for a device that permits odd-length I/O.
Next | Prev | Up | Top | Contents | Index